'use strict';
/**
 * Created by qi on 15/5/16.
 */
angular.module('passwordAgentApp')
  .service('passwordService', function ($rootScope) {
    console.log("-------------passwordService-------------");
    var DEFAULT_LENGTH = 8;
    var UPPER_WORDS = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
    var LOWER_WORDS = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
    var NUMBER_WORDS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
    var WORDS = [
      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
      'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
    ];

    var PATTERN_UPPER_WORD = 'W';
    var PATTERN_LOWER_WORD = 'w';
    var PATTERN_NUMBER_WORD = 'd';

    var salts = [];
    var currentIndex;


    Number.prototype.parseByte = function () {
      var n = this;
      var sign = n & (1 << 7);
      if (sign && n > 0) {
        //n = (n & 0x7F) + 1;
        //n = -n;

        //print("n ======== " + n);
        //n = ~n;
        //n = n + 1;
        n = (~n & 0xff) + 1;
        n = -n;
      }
      return n;
    }

    Number.prototype.parseInt = function () {
      var h = this;
      if (h > 0x7fffffff || 0x80000000) {
        h = h & 0xffffffff;
      }
      return h;
    }

    String.prototype.hashCode = function () {
      var str = this;
      str = str + "";
      var h = 0, off = 0;
      var len = str.length;

      for (var i = 0; i < len; i++) {
        h = 31 * h + str.charCodeAt(off++);
        if (h > 0x7fffffff || 0x80000000) {
          h = h & 0xffffffff;
        }
      }
      return h;
    };

    Array.prototype.hashCode = function () {
      var len = this.length;
      var hashCode = 0;
      for (var i = 0; i < len; i++) {
        hashCode += this[i].hashCode();
        hashCode = hashCode.parseInt();
      }
      return hashCode;
    }

    Array.prototype.addAll = function (anotherArray) {
      //if (!anotherArray.isPrototypeOf(Array)) {
      //  print(anotherArray);
      //  throw "不支持的类型";
      //  return;
      //}
      var thisLength = this.length;
      var len = anotherArray.length;
      for (var i = 0; i < len; i++) {
        this[i + thisLength] = anotherArray[i];
      }
    }


    var passwordService = {};


    //passwordService.newCondition = function(){
    //  console.log("new passwordService.Condition() ==== " + new passwordService.Condition());
    //  return new passwordService.Condition();
    //}

    passwordService.Answer = function () {
      this.ask = "";
      this.answer = "";
      this.hashCode = function () {
        var hashCode = 0;
        hashCode = 37 * hashCode + ((this.ask == null || this.ask.trim == "") ? 0 : this.ask.hashCode()) * 17;
        hashCode = hashCode.parseInt();
        hashCode = 37 * hashCode + ((this.answer == null || this.ask.trim == "") ? 0 : this.answer.hashCode()) * 17;
        return hashCode.parseInt();
      }
    }


    passwordService.Condition = function () {
      this.webSite = "";
      this.answers = [];
      this.email = "";
      this.pattern = "";
      this.length = 8;

      //this.answers.hashCode = function () {
      //  var len = this.length;
      //  var hashCode = 0;
      //  for (var i = 0; i < len; i++) {
      //    hashCode += this[i].hashCode();
      //    hashCode = hashCode.parseInt();
      //  }
      //  return hashCode;
      //}

      this.hashCode = function () {
        var hashCode = 17;
        hashCode = 31 * hashCode + (this.webSite == null ? 0 : this.webSite.hashCode());
        hashCode = hashCode.parseInt();
        hashCode = 31 * hashCode + (this.answers == null ? 0 : this.answers.hashCode());
        hashCode = hashCode.parseInt();
        hashCode = 31 * hashCode + (this.email == null ? 0 : this.email.hashCode());
        hashCode = hashCode.parseInt();
        hashCode = 31 * hashCode + (this.pattern == null ? 0 : this.pattern.hashCode());
        hashCode = hashCode.parseInt();
        hashCode = 31 * hashCode + this.length;
        return hashCode.parseInt();
      }

    }


    passwordService.produceWord = function (condition) {
      //Assert.notNull(condition, "condition不能为空");
      //Assert.notEmpty(condition.getAnswers(), "问题不能为空");
      //Assert.hasText(condition.getWebSite(), "网站不能为空");
      var hashCode = condition.hashCode();
      console.log("hashCode ========== " + hashCode);
      var length = condition.length;
      var pattern = condition.pattern;
      if (pattern == null || pattern == "".trim()) {
        if (length <= 0) {
          length = DEFAULT_LENGTH;
        }

        return produceByLength(hashCode, length);
      } else {
        return produceByPattern(hashCode, pattern);
      }
    }


    function fillDouble(number, length) {
      var wordsLength = WORDS.length;
      var minNumber = Math.pow(wordsLength, length);
      //print(NumberFormat.getInstance().format(wordsLength));
      //print(NumberFormat.getInstance().format(length));
      //print(NumberFormat.getInstance().format(minNumber));

      var hashCodeDouble = number;

      while (hashCodeDouble < minNumber) {
        hashCodeDouble += hashCodeDouble / WORDS.length;
        if (hashCodeDouble < 0) {
          hashCodeDouble = -hashCodeDouble;
        }
      }
      return hashCodeDouble;
    }

    function intToBytes(i) {
      var b = [];
      b[0] = (0xff & i).parseByte();
      b[1] = ((0xff00 & i) >> 8).parseByte();
      b[2] = ((0xff0000 & i) >> 16).parseByte();
      b[3] = ((0xff000000 & i) >> 24).parseByte();
      return b;
    }

    function generateCode(key, bs) {
      var length = bs.length;
      for (var i = 0; i < length; i++) {
        var b = bs[i];
        for (var j = 0; j < length; j++) {
          bs[i] = (bs[j] | b).parseByte();
          bs[i] = (bs[j] ^ b).parseByte();
        }
      }

      var keyLength = key.length;
      var rs = [];
      for (var i = 0; i < keyLength; i++) {
        rs[i] = key[i];
      }
      //System.arraycopy(key, 0, rs, 0, keyLength);
      for (var i = 0; i < keyLength; i++) {
        var k = rs[i];
        for (var j = 0; j < length; j++) {
          rs[i] = (bs[j] ^ k).parseByte();
          rs[i] = (bs[j] | k).parseByte();
        }
      }
      // String string = Base64.encodeBytes(rs);
      // System.out.println(string);
      return rs;
    }

    function doubleToBytes(d, length) {
      var dVar = d;
      var longs = [];
      var value = 2147483647;
      var i = (d % value).parseInt();

//        print(NumberFormat.getInstance().format(d));
      longs.push(i);
      d = d / value;
      var k = 0;
      while (d >= value) {
        i = (d % (value - k++)).parseInt();
//            print(NumberFormat.getInstance().format(d));
        var m = [i];
        longs.addAll(m);
        d = d / value;
      }
      i = (d % (value - k++)).parseInt();
      var m = [i];
      longs.addAll(m);

      var arrayList = [];

      for (var i = 0; i < longs.length; i++) {
        var aLong = longs[i].parseInt();
        console.log("aLong ======== " + aLong);
        var bytes = intToBytes(aLong);
        arrayList.addAll(bytes);
      }

      if (arrayList.length < length) {
        return doubleToBytes(dVar * 2, length);
      }
      //for (Integer aLong : longs) {
      //  var bytes = intToBytes(aLong);
      //  print(bytes);
      //  arrayList.addAll(Arrays.asList(bytes));
      //}

//		while (d > 65535) {
//			arrayList.addAll(Arrays.asList(doubleToBytes(d)));
//		}
      return arrayList;
    }

    function fillSalts(number, length) {
      var wordsLength = WORDS.length;
      var data = Math.pow(wordsLength * 7, length);

      var bs = doubleToBytes(data * length, length);

//        Byte[] bs = randomBytes();
      var key = intToBytes(number);
      var bytes = generateCode(bs, key);
      //print(bytes);
//        EntityHelper.print(bytes);
      salts = bytes;
      console.log("salts ======= " + salts);
      currentIndex = 0;
      //print("salts.length = " + salts.length);
      //print("length = " + length);
    }


    function nextNumber(numberLength) {
      if (currentIndex >= salts.length) {
        throw "数组不够用！";
      }
      var salt = salts[currentIndex++];
//        byte salt = salts[currentIndex];
      if (salt < 0) {
        salt = (-(salt + 1)).parseByte();
      }
//		int saltI = salt;
//		EntityHelper.print(saltI);
//		while (saltI < numberLength) {
//			if (currentIndex >= salts.length - 1) {
//				throw new IndexOutOfBoundsException("数组不够用！");
//			}
//			saltI += salts[++currentIndex];
//			if (saltI < 0) {
//				saltI = -saltI;
//			}
//
//		}

      var rs = salt % numberLength;
//        if (currentIndex < salts.length) {
//            salts[currentIndex] = Byte.parseByte(((((salt - rs) / 11) + salts[currentIndex]) & 0x7F) + "");
//        }

//		if (salt / numberLength != 0) {
//			salts[currentIndex] = (byte) (saltI / numberLength);
//		} else {
//			currentIndex++;
//		}
      return rs;
    }


    function produceByPattern(hashCode, pattern) {
//        Map<Integer, Character> patternMap = new HashMap<Integer, Character>();
//        for (int i = 0; i < pattern.length(); i++) {
//            patternMap.put(i, pattern.charAt(i));
//        }

      var rs = [];
      fillSalts(hashCode, pattern.length);

      for (var i = 0; i < pattern.length; i++) {
        var c = pattern.charAt(i);
        if (c == PATTERN_NUMBER_WORD) {
          var index = nextNumber(10);
          rs[i] = NUMBER_WORDS[index];
        } else if (c == PATTERN_UPPER_WORD) {
          var index = nextNumber(26);
          rs[i] = UPPER_WORDS[index];
        } else if (c == PATTERN_LOWER_WORD) {
          var index = nextNumber(26);
          rs[i] = LOWER_WORDS[index];
        } else {
          throw "表达式错误";
        }

      }

      return rs.join("");

    }

    function produceByPattern2(hashCode, pattern) {
//        Map<Integer, Character> patternMap = new HashMap<Integer, Character>();
//        for (int i = 0; i < pattern.length(); i++) {
//            patternMap.put(i, pattern.charAt(i));
//        }

      var hashCodeDouble = fillDouble(hashCode, pattern.length);
      var rs = [];
      for (var i = 0; i < pattern.length; i++) {
        var c = pattern.charAt(i);
        console.log(c);
        if (c == PATTERN_NUMBER_WORD) {
          var index = Math.floor(hashCodeDouble) % 10;
          hashCodeDouble /= 10;
          rs[i] = NUMBER_WORDS[index];
        } else if (c == PATTERN_UPPER_WORD) {
          var index = Math.floor(hashCodeDouble) % 26;
          hashCodeDouble /= 26;
          rs[i] = UPPER_WORDS[index];
        } else if (c == PATTERN_LOWER_WORD) {
          var index = Math.floor(hashCodeDouble) % 26;
          hashCodeDouble /= 26;
          rs[i] = LOWER_WORDS[index];
        } else {
          throw "表达式错误";
          //throw new IllegalArgumentException("表达式错误");
        }
      }

      return rs.join("");

    }

    function produceByLength(hashCode, length) {
//        Map<Integer, Character> patternMap = new HashMap<Integer, Character>();
//        for (int i = 0; i < pattern.length(); i++) {
//            patternMap.put(i, pattern.charAt(i));
//        }

      fillSalts(hashCode, length);
//		double hashCodeDouble = fillDouble(hashCode, length);
      var wordLength = WORDS.length;

      var rs = [];
      for (var i = 0; i < length; i++) {
        var index = nextNumber(wordLength);
//			int index = (int) (hashCodeDouble % wordLength);
//			hashCodeDouble /= wordLength;
        rs[i] = WORDS[index];
      }

      return rs.join("");

    }

    function produceByLength2(hashCode, length) {
//        Map<Integer, Character> patternMap = new HashMap<Integer, Character>();
//        for (int i = 0; i < pattern.length(); i++) {
//            patternMap.put(i, pattern.charAt(i));
//        }

      var hashCodeDouble = fillDouble(hashCode, length);
      var wordLength = WORDS.length;

      var rs = [];
      for (var i = 0; i < length; i++) {
        var index = Math.floor(hashCodeDouble) % wordLength;
        hashCodeDouble /= wordLength;
        rs[i] = WORDS[index];
      }
      console.log("rs====" + rs);

      return rs.join("");

    }

    //var condition = new Condition();
    //console.log(condition.hashCode());

    return passwordService;
  });
